package net.chasing.androidbaseconfig.widget.arrow;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

import net.chasing.androidbaseconfig.R;
import net.chasing.androidbaseconfig.util.GenericTools;

public class ArrowTextView extends View {
    private static final int CIRCLE_SIZE = 10; //顶角圆形长间距
    private static final int ARROW_HORIZONTAL_EXPAND = 2;

    //箭头相关
    private int mArrowWidth = GenericTools.dip2px(getContext(), 8);
    private int mArrowHeight = GenericTools.dip2px(getContext(), 14);
    private int mBackgroundColor = 0xb3000000;
    private byte mOrientation = ORIENTATION_LEFT;
    private boolean isCircle = true; //顶角是否是圆形
    private Paint mPaint;
    private Path mPath;

    //文字相关
    private String mText;
    private int mTextSize = GenericTools.sp2px(getContext(), 12);
    private int mTextColor = 0xffffffff;
    private int mTextHorizontalPadding = GenericTools.dip2px(getContext(), 8);
    private int mTextVerticalPadding = GenericTools.dip2px(getContext(), 8);
    private int mTextRectWidth;
    private int mTextRectHeight;
    private int mBaseLine;
    private Paint mTextPaint;

    public static final byte ORIENTATION_UP = 0;
    public static final byte ORIENTATION_DOWN = 1;
    public static final byte ORIENTATION_LEFT = 2;
    public static final byte ORIENTATION_RIGHT = 3;

    public ArrowTextView(Context context) {
        this(context, null);
    }

    public ArrowTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ArrowTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        if (attrs != null) {
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
                    R.styleable.ArrowTextView, defStyleAttr, 0);
            int attr;
            for (int i = 0; i < a.getIndexCount(); i++) {
                attr = a.getIndex(i);
                if (attr == R.styleable.ArrowTextView_arrow_text_arrow_background_color)
                    mBackgroundColor = a.getColor(attr, mBackgroundColor);
                else if (attr == R.styleable.ArrowTextView_arrow_text_arrow_orientation) {
                    mOrientation = (byte) a.getInt(attr, mOrientation);
                    switch (mOrientation){
                        case ORIENTATION_UP:
                        case ORIENTATION_DOWN:
                            mArrowWidth = GenericTools.dip2px(getContext(), 14);
                            mArrowHeight = GenericTools.dip2px(getContext(), 6);
                            break;
                        case ORIENTATION_LEFT:
                        case ORIENTATION_RIGHT:
                            mArrowWidth = GenericTools.dip2px(getContext(), 8);
                            mArrowHeight = GenericTools.dip2px(getContext(), 14);
                            break;
                    }
                } else if (attr == R.styleable.ArrowTextView_arrow_text_arrow_is_circle)
                    isCircle = a.getBoolean(attr, isCircle);
                else if (attr == R.styleable.ArrowTextView_arrow_text)
                    mText = a.getString(attr);
                else if (attr == R.styleable.ArrowTextView_arrow_text_size)
                    mTextSize = a.getDimensionPixelSize(attr, mTextSize);
                else if (attr == R.styleable.ArrowTextView_arrow_text_color)
                    mTextColor = a.getColor(attr, mTextColor);
                else if (attr == R.styleable.ArrowTextView_arrow_text_horizontal_padding)
                    mTextHorizontalPadding = a.getDimensionPixelSize(attr, mTextHorizontalPadding);
                else if (attr == R.styleable.ArrowTextView_arrow_text_vertical_padding)
                    mTextVerticalPadding = a.getDimensionPixelSize(attr, mTextVerticalPadding);
            }
            a.recycle();
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setColor(mBackgroundColor);
            mPaint.setStyle(Paint.Style.FILL);

            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setColor(mTextColor);
            mTextPaint.setTextSize(mTextSize);

            if (!TextUtils.isEmpty(mText)) {
                Rect textRect = new Rect();
                mTextPaint.getTextBounds(mText, 0, mText.length(), textRect);
                mTextRectWidth = textRect.width() + 2 * mTextHorizontalPadding;
                mTextRectHeight = textRect.height() + 2 * mTextVerticalPadding;

                //计算baseline
                Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
                float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
                mBaseLine = (int) (mTextRectHeight / 2f + distance);
            }
        }
    }

    public int getActWidth() {
        if (mOrientation == ORIENTATION_UP || mOrientation == ORIENTATION_DOWN) {
            return mTextRectWidth;
        } else if (mOrientation == ORIENTATION_LEFT || mOrientation == ORIENTATION_RIGHT) {
            return mTextRectWidth + mArrowWidth;
        }
        return getWidth();
    }

    public void setOrientation(byte orientation) {
        mOrientation = orientation;
        if (mArrowWidth > 0 && mArrowHeight > 0) {
            createArrowPath();
        }
    }

    public void setText(String text){
        mText = text;
        if (!TextUtils.isEmpty(mText)) {
            Rect textRect = new Rect();
            mTextPaint.getTextBounds(mText, 0, mText.length(), textRect);
            mTextRectWidth = textRect.width() + 2 * mTextHorizontalPadding;
            mTextRectHeight = textRect.height() + 2 * mTextVerticalPadding;

            //计算baseline
            Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
            float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
            mBaseLine = (int) (mTextRectHeight / 2f + distance);
        }
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOrientation == ORIENTATION_UP || mOrientation == ORIENTATION_DOWN) {
            setMeasuredDimension(mTextRectWidth, mTextRectHeight + mArrowHeight);
        } else if (mOrientation == ORIENTATION_LEFT || mOrientation == ORIENTATION_RIGHT) {
            setMeasuredDimension(mTextRectWidth + mArrowWidth, mTextRectHeight);
        }
        createArrowPath();
    }

    private void createArrowPath() {
        mPath = new Path();
        int circleWidth, circleHeight;
        int offsetX, offsetY;
        if (mOrientation == ORIENTATION_UP) {
            offsetX = (mTextRectWidth - mArrowWidth) / 2;
            mPath.moveTo(offsetX, mArrowHeight);
            if (isCircle) {
                circleHeight = CIRCLE_SIZE;
                circleWidth = (int) (mArrowWidth / 2f * circleHeight / mArrowHeight);
                mPath.lineTo(offsetX + mArrowWidth / 2f - circleWidth, circleHeight);
                mPath.quadTo(offsetX + mArrowWidth / 2f, 0,
                        offsetX + mArrowWidth / 2f + circleWidth, circleHeight);
            } else
                mPath.lineTo(offsetX + mArrowWidth / 2f, 0);
            mPath.lineTo(offsetX + mArrowWidth, mArrowHeight);
        } else if (mOrientation == ORIENTATION_DOWN) {
            offsetX = (mTextRectWidth - mArrowWidth) / 2;
            offsetY = mTextRectHeight;
            mPath.moveTo(offsetX, offsetY);
            if (isCircle) {
                circleHeight = CIRCLE_SIZE;
                circleWidth = (int) (mArrowWidth / 2f * circleHeight / mArrowHeight);
                mPath.lineTo(offsetX + mArrowWidth / 2f - circleWidth, offsetY + mArrowHeight - circleHeight);
                mPath.quadTo(offsetX + mArrowWidth / 2f, offsetY + mArrowHeight,
                        offsetX + mArrowWidth / 2f + circleWidth, offsetY + mArrowHeight - circleHeight);
            } else
                mPath.lineTo(offsetX + mArrowWidth / 2f, offsetY + mArrowHeight);
            mPath.lineTo(offsetX + mArrowWidth, offsetY);
        } else if (mOrientation == ORIENTATION_LEFT) {
            offsetY = (mTextRectHeight - mArrowHeight) / 2;
            mPath.moveTo(mArrowWidth, offsetY);
            if (isCircle) {
                circleWidth = CIRCLE_SIZE;
                circleHeight = (int) (mArrowHeight / 2f * circleWidth / mArrowWidth);
                mPath.lineTo(circleWidth, offsetY + mArrowHeight / 2f - circleHeight);
                mPath.quadTo(-ARROW_HORIZONTAL_EXPAND, offsetY + mArrowHeight / 2f,
                        circleWidth, offsetY + mArrowHeight / 2f + circleHeight);
            } else
                mPath.lineTo(0, offsetY + mArrowHeight / 2f);
            mPath.lineTo(mArrowWidth, offsetY + mArrowHeight);
        } else if (mOrientation == ORIENTATION_RIGHT) {
            offsetX = mTextRectWidth;
            offsetY = (mTextRectHeight - mArrowHeight) / 2;
            mPath.moveTo(offsetX, offsetY);
            if (isCircle) {
                circleWidth = CIRCLE_SIZE;
                circleHeight = (int) (mArrowHeight / 2f * circleWidth / mArrowWidth);
                mPath.lineTo(offsetX + mArrowWidth - circleWidth, offsetY + mArrowHeight / 2f - circleHeight);
                mPath.quadTo(offsetX + mArrowWidth + ARROW_HORIZONTAL_EXPAND, offsetY + mArrowHeight / 2f,
                        offsetX + mArrowWidth - circleWidth, offsetY + mArrowHeight / 2f + circleHeight);
            } else
                mPath.lineTo(offsetX + mArrowWidth, offsetY + mArrowHeight / 2f);
            mPath.lineTo(offsetX, offsetY + mArrowHeight);
        }
        mPath.close();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mPaint != null && mPath != null)
            canvas.drawPath(mPath, mPaint);
        if (mTextPaint != null && !TextUtils.isEmpty(mText)) {
            if (mOrientation == ORIENTATION_UP) {
                canvas.drawRoundRect(0, mArrowHeight, mTextRectWidth, mArrowHeight + mTextRectHeight,
                        GenericTools.dip2px(getContext(), 4), GenericTools.dip2px(getContext(), 4), mPaint);
                canvas.drawText(mText, mTextHorizontalPadding, mBaseLine + mArrowHeight, mTextPaint);
            } else if (mOrientation == ORIENTATION_DOWN) {
                canvas.drawRoundRect(0, 0, mTextRectWidth, mTextRectHeight,
                        GenericTools.dip2px(getContext(), 4), GenericTools.dip2px(getContext(), 4), mPaint);
                canvas.drawText(mText, mTextHorizontalPadding, mBaseLine, mTextPaint);
            } else if (mOrientation == ORIENTATION_LEFT) {
                canvas.drawRoundRect(mArrowWidth, 0, mArrowWidth + mTextRectWidth, mTextRectHeight,
                        GenericTools.dip2px(getContext(), 4), GenericTools.dip2px(getContext(), 4), mPaint);
                canvas.drawText(mText, mArrowWidth + mTextHorizontalPadding, mBaseLine, mTextPaint);
            } else if (mOrientation == ORIENTATION_RIGHT) {
                canvas.drawRoundRect(0, 0, mTextRectWidth, mTextRectHeight,
                        GenericTools.dip2px(getContext(), 4), GenericTools.dip2px(getContext(), 4), mPaint);
                canvas.drawText(mText, mTextHorizontalPadding, mBaseLine, mTextPaint);
            }
        }
    }
}